﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CNShapes;
using System.Drawing;

namespace CNShapeViewer
{
    /// <summary>
    /// Renders the Shape_Arrow shape.
    /// </summary>
    class ShapeRenderer_Arrow : IShapeRenderer
    {
        #region Public methods

        /// <summary>
        /// We draw the arrow using the data from the shape passed in.
        /// </summary>
        public void renderShape(Shape shape, Graphics graphics, ShapeViewerControl shapeViewerControl)
        {
            Shape_Arrow arrowShape = (Shape_Arrow)shape;

            // We find the start and end points in screen coordinates...
            PointF clientStart = shapeViewerControl.shapePointToClientPoint(arrowShape.StartPoint);
            PointF clientEnd = shapeViewerControl.shapePointToClientPoint(arrowShape.EndPoint);

            // We get the pen, and amend it to have an arrow tip...
            Pen pen = RendererHelper.getPen(arrowShape, shapeViewerControl);
            pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;

            // We draw the arrow...
            graphics.DrawLine(pen, clientStart, clientEnd);

            // We draw the arrow head...
            PointF arrowStart = getArrowStart(clientEnd, clientStart);
            pen.Width *= 2.5f;
            graphics.DrawLine(pen, arrowStart, clientEnd);
        }

        /// <summary>
        /// Returns the type of shape we're managing.
        /// </summary>
        public Type getShapeType()
        {
            return typeof(Shape_Arrow);
        }

        #endregion

        #region Private functions

        /// <summary>
        /// Returns a point near the _start_ of the arrow, 1 pixel away
        /// from the start. If you draw an line with an arrow end-cap from 
        /// this point to the start, it will point to the start.
        /// </summary>
        private PointF getArrowStart(PointF start, PointF end)
        {
            float a = end.X - start.X;
            float b = end.Y - start.Y;

            if (a == 0f)
            {
                return new PointF(start.X, start.Y + 1 * Math.Sign(b));
            }

            double a2 = a * a;
            double b2 = b * b;
            double c2 = a2 / (a2 + b2);
            double c = Math.Sqrt(c2) * Math.Sign(a);
            double d = b / a * c;
            c += start.X;
            d += start.Y;

            return new PointF((float)c, (float)d);
        }

        #endregion
    }
}
